package architecture.impl;

import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import architecture.beans.AbstractEntity;
import architecture.interfaces.GenericDao;

@Repository
@Transactional
public abstract class GenericImpl<T extends AbstractEntity<K>, K> implements GenericDao<T, K> {

	@PersistenceContext
	protected EntityManager entityManager;

	private Class<T> clase;

	public GenericImpl() {
		setClaseFromInherited();
	}

	@SuppressWarnings("unchecked")
	private void setClaseFromInherited() {
		clase = (Class<T>) ((ParameterizedType) (this.getClass().getGenericSuperclass())).getActualTypeArguments()[0];
	}

	/**
	 * Metodo para guardar la entidad, si existe har� un update y si no existe un insert
	 * 
	 * @param entidad
	 *            entidad que deseamos guardar
	 */
	public void save(final T entidad) {
		if (entidad.getId() != null) {
			insert(entidad);
		} else {
			update(entidad);
		}
	}

	/**
	 * Entidad que deseamos eliminar de la base de datos
	 * 
	 * @param entidad
	 */
	public void delete(T entidad) {
		entidad = entityManager.find(clase, entidad.getId());

		if (entidad != null) {
			entityManager.remove(entidad);
		}
	}

	/**
	 * Entidad que deseamos buscar por id
	 * 
	 * @param id
	 */
	public T find(final K id) {
		return entityManager.find(clase, id);
	}

	/**
	 * Listar todos los registros de la tabla
	 * 
	 */
	public List<T> findAll() {
		return entityManager.createQuery("select e from " + clase.getName() + " e", clase).getResultList();
	}

	/**
	 * Insertamos un nuevo registro en la base de datos
	 * 
	 * @param entidad
	 */
	public void insert(final T entidad) {
		entityManager.persist(entidad);
	}

	/**
	 * Actualizamos un nuevo registro en la base de datos
	 * 
	 * @param entidad
	 */
	public void update(final T entidad) {
		entityManager.merge(entidad);
	}

}